
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections;
using System.Text;
using Swaf;
using Swaf.BizObj;
using Swaf.BizRule;
using System.Diagnostics;

using Swaf.Container;
using Swaf.Security;
using Swaf.Logging;

namespace UserLogin
{
    /// <summary>
    /// Provides basic read-only access to user login functionality.  User management bizrules are
    /// located in the UserManager.BusinessRules class.
    /// All of the bizrules within this class will throw UserLoginException if a failure occurs.
    /// </summary>
    public class BusinessRules : Syrinx.BaseBizRules
    {
		public bool checkCurrentUserAgainstUiViewName(IApplication app, IRuleContext context, string uiViewName)
		{
			bool didChange = false;
			string[] nameParts = uiViewName.Split('_');
			IBizObj company = null;
			if (nameParts.Length > 2)
			{
				string shortName = nameParts[0];
				company = context.RuleGroup.execute("getCompanyByShortName", shortName).CallResults as IBizObj;
				app.Log.println(LoggingLevels.Medium, "checkCurrentUserAgainstUiViewName-a:{0}:{1},{2}",uiViewName, shortName, company==null);
			}
			else
			{
				Swaf.BGuid.Guid rootCompanyId = (Swaf.BGuid.Guid)app.appData.get("userLoginOptions.rootCompanyId");
				company = context.RuleGroup.execute("getCachedCompanyInfo", rootCompanyId).CallResults as IBizObj;
				app.Log.println(LoggingLevels.Medium, "checkCurrentUserAgainstUiViewName-b:{0}:{1}", uiViewName, company == null);
			}

			IResults rc = null;
			if (didChange = (company != null && ActiveCompanyId.CompareTo(company.get("id")) != 0))
			{
				rc = context.RuleGroup.execute("loginAnonymousUser", company.get("id"));
				if (rc != null && rc.CallResults is UserLogin.LoginResult)
				{
					UserLogin.LoginResult lr = (UserLogin.LoginResult)rc.CallResults;
					app.Log.println(LoggingLevels.Medium, "checkCurrentUserAgainstUiViewName-c:{0}:{1}:{2}", uiViewName, ActiveCompany.get("shortName"), company.get("shortName"));
				}
			}

			return didChange;
		}

		public string getUserTemplateName(IApplication app, IRuleContext context, IBizObj user)
		{
			return "UserManagement.AspNet.UserDetailDisplay";
		}
        /// <summary>
        /// this bizrule will login the default anonymous user login based on the company id
        /// provided. If the anonymous user is succussfully logged in, the current CSF session's
        /// securityMgr.currentPrinciple will be setup from the anonymous user info in the
        /// data store.</summary>
        /// <param name="companyId">The id of the company the anonymous user is associated with.  If null,
        /// the root company id will be used, which is the company that has no parent id. </param>
        public LoginResult loginAnonymousUser(IApplication app, IRuleContext context,Swaf.BGuid.Guid companyId)
        {
            try
            {
				if(companyId == null)
					companyId = app.sessionData["companyId"] as Swaf.BGuid.Guid;
                if (companyId == null)
                    companyId = getDefaultCompanyId(app, context);
				Debug.Assert(companyId!= null);

                FlexiMap m = new FlexiMap();
                m.put("id", companyId);
                IBizObjList list = (IBizObjList)app.appData.get("Data.UserLogin.GetAnonymousInfo", m);
				
				if (list.numElements == 0)
                    throw new UserLoginException("Error executing anonymous login. No default anonymous account exist.");
                IBizObj anon = (IBizObj)list[0];

				IResults rc = app.ruleMgr.execute("loginUserAdvanced", anon, companyId!=null);
				if (rc.ExceptionInfo != null)
					throw new UserLoginException("error executing loginUser bizrule", rc.ExceptionInfo);
               
                return rc.CallResults as LoginResult;
            }
			catch (UserLoginException e) { throw e; }
			catch (Exception e)
            {
                throw new UserLoginException("Error executing UserLogin.setupAnonUser", e);
            }
        }

        /// <summary>
        /// This bizrule will calculate a company id based on the url used to access the web tier by using
        /// the "firstUrl" that may be contained wtihin the app.sessionData.  If that isn't present, then the
        /// app.appData["userLoginOptions.rootCompanyId"] will be used.
        /// </summary>
        /// <returns>The default company id</returns>
        public Swaf.BGuid.Guid getDefaultCompanyId(IApplication app, IRuleContext context)
        {
            Uri userPathInfo = app.sessionData["firstUrl"] as Uri;
            Swaf.BGuid.Guid companyId = (Swaf.BGuid.Guid)app.appData.get("userLoginOptions.rootCompanyId");
            if (userPathInfo != null)
            {
                FlexiMap m = new FlexiMap();
                m["hostName"] = userPathInfo.Host.ToLower();
                string path = userPathInfo.LocalPath;
                int index = path.IndexOf('/',1);
                if (index != -1)
                    m["virtualName"] = "ANY_HOST" + path.Substring(0, index).ToLower();
                else
                    m["virtualName"] = "";
                IBizObjList companies = app.appData.get("Data.UserLogin.GetDefaultCompanyIdFromPath", m) as IBizObjList;
                if (companies != null && companies.numElements > 0)
                    companyId = companies[0].get("id") as Swaf.BGuid.Guid;
            }
            return companyId;
        }

		public LoginResult loginUser(IApplication app, IRuleContext context, IBizObj user)
		{
			return loginUserAdvanced(app, context, user, false);
		}

        /// <summary>
        /// This bizrule will attempt to logon the user based on the userid and password given in the User 
        /// bizobj parameter. The bizrule will return the results of the attempt to validate the user
        /// login using an UserLoginResult value.  If the login attempt was successful, the given user
        /// will become the current CSF session's user and the session's securityMgr.currentPrinciple
        /// will be setup from it.
        /// </summary>
        /// <param name="user">The user id and password needed to attempt to password in a User bizobj.</param>
        /// <returns>The success or failure results of the login attempt.</returns>
        public LoginResult loginUserAdvanced(IApplication app, IRuleContext context, IBizObj user, bool restablishSession)
        {
			try
			{
				Debug.Assert(user!=null);
                IBizObj company = null;
                IResults rc = null;

                string userName = user.get("userName").ToString();
                int index = userName.IndexOf('@');
                if (index != -1)
                {
                    user.put("userName", userName.Substring(0,index));
                    string companyShortName = userName.Substring(index + 1);
                    rc = app.ruleMgr.execute("getCompanyByShortName", companyShortName);
                    company = rc.CallResults as IBizObj;
                    if (company != null)
                        user.put("companyId", company.get("id"));

                }
				if (user.get("companyId") == null)
					user.put("companyId", ActiveCompanyId);
                    //user.put("companyId", getDefaultCompanyId(app, context));

				IBizObjList users = null;
				if(restablishSession)
					users = (IBizObjList)app.appData.get("Data.UserLogin.GetUserFromUserNameOnly", user);
				else
					users = (IBizObjList)app.appData.get("Data.UserLogin.ValidateUser", user);
				Debug.Assert(users != null);
                LoginResult lr = new LoginResult();
                if (users.numElements != 0)
                {
                    user = (IBizObj)users[0];
                    if ((bool)user.get("enable") == false)
                        lr.UserLoginResultInfo = UserLoginResult.UserAccountDisabled;

                    if (company == null)
                    {
                        rc = app.ruleMgr.execute("getCompany", user.get("companyId"));

                        if (rc.ExceptionInfo != null)
                            throw new UserLoginException("loginUser bizRule Error.", rc.ExceptionInfo);
                        else
                        {
                            Debug.Assert(rc.CallResults is IBizObj);
                            company = rc.CallResults as IBizObj;
                        }
                    }
					if (lr.UserLoginResultInfo != UserLoginResult.UserAccountDisabled && company != null)
					{
						rc = app.ruleMgr.execute("companyIsActive", company.get("id"), company.get("parentId"));

						if (rc.ExceptionInfo != null)
							throw new UserLoginException("loginUser.companyIsActive bizrule call error.", rc.ExceptionInfo);

						Debug.Assert(rc.CallResults is bool);
						if ((bool)rc.CallResults == false)
							lr.UserLoginResultInfo = UserLoginResult.UserCompanyDisabled;

						bool isAnon = user.get("id").Equals(company.get("anonymousId"));
						user.put("authenticated", !isAnon);
						FlexiMap m = new FlexiMap();
						m.put("userId", user.get("id"));
						IBizObjList userGroups = (IBizObjList)app.appData.get("DA.UserLogin.GetUserUserGroups", m);

						//Get user specific privileges
						m.put("id", user.get("id"));
						IBizObj userGroup = app.appData.get("DA.UserLogin.GetUserPrivileges", m) as IBizObj;
						if (userGroup != null)
							userGroups.Add(userGroup);

						IBizObj userLogin;

						IUserLoginManager ulm = (IUserLoginManager)app.appData.get("sysObjs-UserLogin");
						user = ulm.userActive(user, userGroups);
						ulm.principalActive(this.createPrinciple(user));
						lr.UserLoginResultInfo = UserLoginResult.ValidUserPassword;

						// setup the user limits
						IBizObj limits = app.appData.get("DA.UserLogin.GetUserLimits", m) as IBizObj;
						if (limits == null)
							throw new UserLoginException("Unable to find user with provided id");
						user.put("limits", limits);

						// setup the user preferences information
						rc = app.ruleMgr.execute("getUserPreferences",
							(Swaf.BGuid.Guid)user.get("id"));
						if (rc.ExceptionInfo != null)
							throw rc.ExceptionInfo;
						lr.UserPreferenceInfo = rc.CallResults as IBizObj;
						if (lr.UserPreferenceInfo != null)
							CurrentUser.put("settings", rc.CallResults);
						else
							((IBizObj)CurrentUser.get("settings")).isNew = true;

                        app.ruleMgr.execute("updateUserActivity");
						if(!restablishSession)
							app.ruleMgr.execute("updateSessionState", false);
					}
				}
                else
                {
                    lr.UserLoginResultInfo = UserLoginResult.InvalidUserPassword;
                }
                return lr;
            }
            catch (UserLoginException e) {throw e;}
            catch (Exception e)
            {
                throw new UserLoginException("Error executing UserLogin.setupAnonUser", e);
            }
        }

        /// <summary>
        /// This method will deactivate the current user login and call the loginAnonymousUser
        /// bizrule to ensure the anonymous user is still active.
        /// </summary>
        public void logoffUser(IApplication app, IRuleContext context, bool sessionEnd)
        {
            IUserLoginManager ulm = (IUserLoginManager)app.appData.get("sysObjs-UserLogin");
            ISecurityPrincipal user = CurrentPrincipal;

            ulm.principalDeactive(user);
            if(!sessionEnd)
                app.ruleMgr.execute("loginAnonymousUser", user.additionalInfo.get("companyId"));
        }

        public void sessionLogoffUser(IApplication app, IRuleContext context, IApplication sessionApp)
        {
            logoffUser(app, context, true);
        }

        public void updateUserActivity(IApplication app, IRuleContext context)
        {
            try
            {
                DateTime n = DateTime.UtcNow;
                IBizObj user = app.securityMgr.currentPrincipal.additionalInfo as IBizObj;
                if (user == null || app.sessionData.get("browserInfo") == null)
                    return;
                IBizObj userLogin = app.bizObjMgr.create("UserLogin");
                userLogin.put("sessionId", app.sessionId);
                userLogin.put("user", user);
                userLogin.put("loginTime", n);
                userLogin.put("lastAccessTime", n);
                userLogin.put("anonUser", !(bool)user.get("authenticated"));
                userLogin.put("browserInfo", app.sessionData.get("browserInfo"));
                string referrer = app.sessionData.get("referrer") as string;
                if(referrer == null)
                    referrer = "";
                userLogin.put("referrer", referrer);
                userLogin.put("userIPAddresses", app.sessionData.get("userIP"));
                int numAffected = (int)app.appData.get("DA.UserLogin.UpdateUserLastAccess", userLogin);

                if (numAffected == 0)
                    app.appData.put("DA.UserLogin.AddNewUserLogin", userLogin);
            }
            catch
            {
                //TODO: What should happen if we cannot update the anon user being logged off for a
                //user login.
            }
        }

		/// <summary>
		/// Creates a single bizobj list of app function bizobjs each with a security privilege
        /// based on the given user's user group membership.  If the user is a member of
        /// multiple user groups that have a privilege set for the same app function this
        /// bizrule will only add the app function into the bizobj list once using the highest
        /// privilege level of the user groups.
		/// </summary>
		/// <param name="user">The User bizobj to create the app function bizobj list from</param>
		/// <returns>The app function bizobj list of the user's security privileges</returns>
		public IBizObjList getUserAppFunctionPrivilages(IApplication app, IRuleContext context, IBizObj user)
        {
            IBizObjList appFunctions =App.bizObjMgr.createSource(SourceType.BasicSource, "").getList("AppFunction", "");

            foreach (IBizObj userGroup in (IList)user.get("groups"))
                foreach (IBizObj appFun in (IList)userGroup.get("appPrivileges"))
                {
                    bool found = false;
                    foreach (IBizObj exFun in appFunctions)
                    {
						if (exFun.get("id") == appFun.get("id") && (int)exFun.get("privilege") < (int)appFun.get("privilege"))
						{
							exFun.put("privilege", appFun.get("privilege"));
							exFun.put("depth", 1);
							found = true;
							break;
						}
                    }
					if (!found)
					{
						IBizObj clone = appFunctions.insertNewMakeCopy(appFun);
						clone.put("depth", 1);
					}
                }

            return appFunctions;
        }

        /// <summary>
        /// Exposes the various settings defined in the application's CSF configuration for
        /// the user login feature.  These settings are kept within the "userLoginOptions"
        /// name and the option passed into this bizrule is tacked onto that name and the
        /// resulting value is returned.  For example, if the option value is set to
        /// "defaultPrivilegeLevel", this method will return whatever is stored in the
        /// app.appData["userLoginOptions.defaultPrivilegeLevel"] AOM.
        /// </summary>
        /// <remarks>The reason for having a bizrule that simply returns something
        /// from the AOM is to help support a distributed environment.  If a bizproc
        /// in the web tier wants this info and the user login feature is running in
        /// a different tier, this allows the web tier to make a remote call to get the
        /// value rather then forcing the web tier to have a copy of these values in 
        /// its own AOM.</remarks>
        /// <param name="option">The user login option to be retrieved</param>
        /// <returns>The user login option requested or null if the given option does
        /// is not contained in the AOM.</returns>
		public object getUserLoginOption(IApplication app, IRuleContext context, string option)
		{
			return app.appData.get("userLoginOptions." + option);
		}

        /// <summary>
        /// Returns the complete set of defined app functions specific to the given company.
        /// Because some app functions are derived from data that is specific to a company,
        /// the specific set of app functions available is different for each company.  Users
        /// that login to the application will have this set of app functions avialable to
        /// have privileges set for them.  As a result, this list can change during runtime
        /// as new data is added to the application.
        /// </summary>
        /// <remarks>Typically, when a UI exposes data that is associated with a security
        /// privilege, the UI will check the user's privilege level for that data and not
        /// allow the user to take action against the data that is not within their privilege
        /// level.  Also, bizrules that retrieve data that is associated with a security
        /// privilege will typically filter out data that the user has less then a ReadOnly
        /// privilege level for.</remarks>
        /// <returns>The company specific app functions that exist at the time of the
        /// rule call.</returns>
        public IBizObjList getCompanyAppFunctions(IApplication app, IRuleContext context)
		{
			return LoginMgr.getCompanyAppFunctions(ActiveCompanyId);
		}

		public IBizObjList getPrivilegeLevels(IApplication app, IRuleContext context)
		{
			IBizObjList list = getUserLoginOption(app, context, "privilegeLevels") as IBizObjList;
			foreach (IBizObj obj in list)
				if ("Derived".Equals(obj.get("name").ToString()) || "Execute".Equals(obj.get("name").ToString()))
					list.Remove(obj);
			return list;
		}
		public IBizObjList getSpecificCompanyAppFunctions(IApplication app, IRuleContext context,Swaf.BGuid.Guid companyId, IBizObj filter)
		{
			//TODO: Someday we need to really care about the filtersort
			IBizObjList groups = LoginMgr.getCompanyAppFunctions(companyId);
			return groups;
		}

        /// <summary>
        /// Given a name of a company, this method will return the detailed Company bizobj
        /// for it.  Company names should be unique in the data store, but if more
        /// then one company shares the same name, the first one returned from the data store
        /// will be returned.
        /// </summary>
        /// <param name="companyName">The name of the company to search for.</param>
        /// <returns>The detailed company bizobj or null if not found.</returns>
        public IBizObj getCompanyByShortName(IApplication app, IRuleContext context, string companyShortName)
        {
            try
            {
                FlexiMap m = new FlexiMap();
				m.put("companyShortName", companyShortName);

                IBizObjList companies = (IBizObjList)app.appData.get("Data.UserLogin.GetCompanyByName", m);
                if (companies.numElements > 0)
                    return (IBizObj)companies[0];
                else
                    return null;
            }
            catch (Exception e)
            {
                throw new UserLoginException("Error executing getCompanyByName bizrule", e);
            }
        }

        /// <summary>
        /// Companies can have child companies that ultimately form a tree parent/child
        /// company relationship.  This bizrule will return a list of companies that are children
        /// of the given company.
        /// </summary>
        /// <param name="companyId">The id of the company to return the child companies for</param>
        /// <param name="deepSearch">If true, this bizrule will return all of the child
        /// companies within the tree that may exist of parent/child companies below the
        /// given company.  If false, this bizrule will only return the direct children
        /// of the given company.</param>
        /// <returns>The bizobj list of Company bizobjs or null if the company has none
        /// or if the company id is invalid.</returns>
        public IBizObjList getChildCompanies(IApplication app, IRuleContext context, Swaf.BGuid.Guid companyId, bool deepSearch)
        {
            try
            {
                if (companyId == null)
                    companyId = getDefaultCompanyId(app,context);
                FlexiMap m = new FlexiMap();
                m.put("parentId", companyId);
				object companies = app.appData.get((deepSearch) ? "DA.UserLogin.GetCompanyTree" : "Data.UserLogin.GetChildCompanies", m);
				return (IBizObjList)companies;
            }
            catch (Exception e)
            {
                throw new UserLoginException("Error executing getChildCompanies bizrule", e);
            }
        }

		/// <summary>
		/// get the company information and call getChildCompanies to return the company search result
		/// </summary>
		/// <param name="app"></param>
		/// <param name="context"></param>
		/// <param name="searchOption"></param>
		/// <returns></returns>
		public IBizObjList getCompanySearchResult(IApplication app, IRuleContext context, IBizObj searchOption,bool deepSearch)
		{
			try
			{
				IBizObjList options = searchOption.get("filterOptions") as IBizObjList;
				FlexiMap m = new FlexiMap();
				m["criteria"] = "like '%'";
				string dar = "GetCompanyTree";
				foreach (IBizObj option in options)
				{
					if (option.get("field").ToString().ToUpper() == "ALL")
						continue;
					if ("company".Equals(option.get("field").ToString().ToLower()))
					{
						string val = option.get("value").ToString();
						int i = Convert.ToInt16(option.get("criteria"));
						if (i == 1)
							m["criteria"] = string.Format("='{0}'", val);
						else if (i == 2)
							m["criteria"] = string.Format("like '%{0}%'", val);
						else if (i == 3)
							m["criteria"] = string.Format("like '{0}%'", val);
						else if (i == 4)
							m["criteria"] = string.Format("like '%{0}'", val);
						dar = "GetCompanySearchResult";
						break;
					}
					else
						continue;
				}
				
				return app.appData.get(string.Format("Data.UserLogin.{0}",dar), m) as IBizObjList;
			}
			catch (Exception e)
			{
				throw new UserLoginException("Error executing getCompanySearchResult bizrule.", e);
			}

		}
        /// <summary>
        /// Given a company id, this bizobj will return a detailed Company bizobj for it.
        /// </summary>
        /// <param name="companyId">The company id to search for</param>
        /// <returns>The detailed Company bizobj if the id is found in the data store or null
        /// if the id is not.</returns>
        public IBizObj getCompany(IApplication app, IRuleContext context, Swaf.BGuid.Guid companyId)
        {
            try
            {
				FlexiMap m = new FlexiMap();
				m.put("companyId", companyId);
                IBizObj company = app.appData.get("DA.UserLogin.GetCompany", m) as IBizObj;
				if (company != null)
				{
					company.put("settings.id", company.get("id"));
					IBizObj companySettings = app.appData.get("DA.UserLogin.GetCompanySettings", company) as IBizObj;
					if (companySettings != null)
						company.put("settings", companySettings);
					else
						((IBizObj)company.get("settings")).isNew = true;
					IResults rc = context.RuleGroup.execute(context, "getContactDetail", companyId);
					if (rc.CallResults is IBizObj)
						company.put("contact", rc.CallResults);
				}

                return company;
            }
            catch (Exception e)
            {
                throw new UserLoginException("Error executing getCompany bizrule", e);
            }
        }

		public IBizObjList getCompanyParents(IApplication app, IRuleContext context, Swaf.BGuid.Guid companyId)
		{
			FlexiMap m = new FlexiMap();
			m["id"] = companyId;
			IBizObjList parents = app.appData.get("DA.UserLogin.GetCompanyParentPath", m) as IBizObjList;
			return parents;
		}

		public IBizObj getCachedCompanyInfo(IApplication app, IRuleContext context, Swaf.BGuid.Guid companyId)
		{
			IBizObj company = app.appData.get(companyId.ToString()) as IBizObj;
			if (company == null)
				lock (this.GetType())
					if ((company = app.appData.get(companyId.ToString()) as IBizObj) == null)
						app.appData.put(companyId.ToString(), company = context.RuleGroup.execute("getCompany", companyId).CallResults as IBizObj);
			return company;
		}

		public void clearCachedCompanyInfo(IApplication app, IRuleContext context, Swaf.BGuid.Guid companyId)
		{
			app.appData.put(companyId.ToString(), null);
		}

        /// <summary>
        /// This bizrule will determine if the given company is active.  If a company is not active,
        /// its users cannot login to the application.  Because of the parent/child relationship of
        /// companies, if a parent company is not active, none of its child companies are active either.
        /// </summary>
        /// <param name="companyId">The id of the company being checked</param>
        /// <param name="parentId">The parent id of the company being checked or null if this
        /// company has no parent company.</param>
        /// <returns>True if the company is active or false if it is not or if the company id
        /// is not known in the data store.</returns>
        public bool companyIsActive(IApplication app, IRuleContext context, 
            Swaf.BGuid.Guid companyId,Swaf.BGuid.Guid parentId)
        {
            try
            {
                FlexiMap m = new FlexiMap();
                m.put("parentId", parentId);
                m.put("id", companyId);
                IBizObjList l = (IBizObjList)app.appData.get("Data.UserLogin.GetCompanyParentPathStatus", m);
                return (l.numElements == 0) ? true : false;
            }
            catch (Exception e)
            {
                throw new UserLoginException("Error executing companyIsActive Bizrule.", e);
            }
        }

        /// <summary>
        /// Returns the current user session's securityMgr.currentPrincipal.  This bizrule
        /// is intented to be called remotely when another tier in the application wants the 
        /// details of the user from the tier that is hosting the user login feature.
        /// </summary>
        /// <returns>The current session's securityMgr.currentPrincipal.</returns>
        public ISecurityPrincipal getRemoteSecurityPrincipal(IApplication app, IRuleContext context)
		{
            return Application.currentApp.securityMgr.currentPrincipal;
		}
        /// <summary>
        /// 
        /// </summary>
        /// <param name="app"></param>
        /// <param name="context"></param>
        /// <param name="userId"></param>
        /// <param name="companyId"></param>
        /// <returns>UserPreferences BizObj</returns>
        public IBizObj getUserPreferences(IApplication app, IRuleContext context, Swaf.BGuid.Guid userId)
        {
            try
            {
				FlexiMap m = new FlexiMap();
				m.put("userId", userId);
				IBizObj userSettings = app.appData.get("DA.UserLogin.GetUserSettings", m) as IBizObj;
				if (userSettings == null)
				{
					userSettings = app.bizObjMgr.create("UserSettings");
					userSettings.put("id", userId);
				}
				return userSettings;
            }
            catch (Exception e)
            {
                throw new UserLoginException("Error executing getUserPreferences bizRule.", e);
            }

        }

        public IBizObjList getUserLogins(IApplication app, IRuleContext context, FlexiMap dates)
        {
            try
            {
                IBizObjList userLogins = app.appData.get("Data.UserLogin.GetUserLogins", dates) as IBizObjList;
                return userLogins;
            }
            catch (Exception e)
            {
                throw new UserLoginException("Error executing getUserLogins bizRule.", e);
            }
        }

        public IBizObjList getUserLoginTotals(IApplication app, IRuleContext context, FlexiMap dates)
        {
            IBizObjList userLoginTotals = app.bizObjMgr.createList("UserLoginTotals");
            try
            {
                IBizObjList userLogins = app.appData.get("Data.UserLogin.getUserLogins", dates) as IBizObjList;
                if (userLogins != null)
                {
                    IBizObj currentTotal = null;
                    foreach (IBizObj userLogin in userLogins)
                    {
                        DateTime dayLoggedIn = (DateTime)userLogin.get("loginTime");
                        dayLoggedIn = new DateTime(dayLoggedIn.Year, dayLoggedIn.Month, dayLoggedIn.Day);
                        if (currentTotal == null || !currentTotal.get("date").Equals(dayLoggedIn))
                        {
                            currentTotal = userLoginTotals.insertNew();
                            currentTotal.put("date", dayLoggedIn);
                        }
                        string fld = (bool)userLogin.get("anonUser") ? "totalAnonymousSessions" : "totalAuthenticatedSessions";
                        int newTotal = (int)currentTotal.get(fld);
                        currentTotal.put(fld, ++newTotal);
                    }
                }

                return userLoginTotals;
            }
            catch (Exception e)
            {
                throw new UserLoginException("Error executing getUserLogins bizRule.", e);
            }
        }

		public IBizObjList getCompanySettingsDbFields(IApplication app, IRuleContext context)
		{
			IBizObjList settingsFields = app.bizObjMgr.createList("DataAccessFieldInfo");

			IBizObj autoSignup = settingsFields.insertNew();
			autoSignup.put("dbName", "autoSignupEnabled");
			autoSignup.put("bizObjName", "autoSignupEnabled");
			autoSignup.put("aliasName", "autoSignupEnabled");
			autoSignup.put("dbType", "Boolean");
			IBizObj sitePath = settingsFields.insertNew();
			sitePath.put("dbName", "sitePath");
			sitePath.put("bizObjName", "sitePath");
			sitePath.put("aliasName", "sitePath");
			sitePath.put("dbType", "UnicodeVarChar");
            IBizObj domainNames = settingsFields.insertNew();
            domainNames.put("dbName", "domainNames");
            domainNames.put("bizObjName", "domainNames");
            domainNames.put("aliasName", "domainNames");
            domainNames.put("dbType", "VarChar");

            return settingsFields;
		}

		public Swaf.Gui.CompanyDomainInfo getCompanyFromDomainName(IApplication app, IRuleContext context, Uri url)
		{
			Swaf.Gui.CompanyDomainInfo info = new Swaf.Gui.CompanyDomainInfo(null, true);
			string host = url.Host;
			if (url.Port != 80)
				host += ":" + url.Port;
            string hostName = "," + host + ",";
			string keyName = hostName.Replace('.', '_');
            FlexiMap m = app.appData.get("companyHostNames") as FlexiMap;
            if (m == null)
                lock (GetType())
                    if ((m = app.appData.get("companyHostNames") as FlexiMap) == null)
                        app.appData.put("companyHostNames", m = new FlexiMap());

			Swaf.BGuid.Guid companyId = m.get(keyName) as Swaf.BGuid.Guid;
            IBizObj company = null;
			if (companyId == null)
			{
				m.put("domainName", hostName);
				IBizObj basicCompany = app.appData.get("DA.UserLogin.GetCompanyFromDomainName", m) as IBizObj;
				if (basicCompany != null)
				{
					app.Log.println(LoggingLevels.Medium, "getCompanyFromDomainName: Company: '{0}' Based on Uri: {1}", basicCompany.get("name"), url);
					companyId = basicCompany.get("id") as Swaf.BGuid.Guid;
				}
				m.put(keyName, companyId);
			}

			if (companyId != null)
			{
				//Now check for child company based on path name.
				string subname = null;
				string path = url.PathAndQuery.Substring(1);
				int i = path.IndexOf("?pi=");
				if (i != -1)
				{
					int l = i+"?pi=".Length;
					int pp = path.IndexOf("/", l);
					if (pp == -1)
						pp = path.IndexOf("&", l);
					subname = path.Substring(l, pp - l);
				}
				else
				{
					i = path.IndexOf('/');
					if (i != -1)
						subname = path.Substring(0, i);
				}
				if(subname != null)
				{
					if (subname.CompareTo("filesys") == 0 || subname.CompareTo("img") == 0)
					{
						subname = path.Substring(i + 1, path.IndexOf('/', i + 1)-i-1);
					}
					//Note that getcompanyByShortName only gets the id and not the full basic company info.
					//So still need to call getCachedCompanyInfo below to get the full info from teh companyId
					company = Swaf.Application.globalApp.ruleMgr.execute("getCompanyByShortName", subname).CallResults as IBizObj;
					if (company != null)
					{
						app.Log.println(LoggingLevels.Medium, "getCompanyFromDomainName: Company: '{0}'  Based on short name '{1}' - Uri: {2}", company.get("name"), subname, url);
						companyId = (Swaf.BGuid.Guid)company.get("id");
						info.UsingCompanyUrl = false;
					}
				}
				company = context.RuleGroup.execute("getCachedCompanyInfo", companyId).CallResults as IBizObj;
			}
			info.Company = company;
			return info;
		}

		public IBizObjList getUserSettingsDbFields(IApplication app, IRuleContext context)
		{
			IBizObjList settingsFields = app.bizObjMgr.createList("DataAccessFieldInfo");

			return settingsFields;
		}

		public IBizObjList getUserLimitsDbFields(IApplication app, IRuleContext context)
		{
			IBizObjList settingsFields = app.bizObjMgr.createList("DataAccessFieldInfo");

			return settingsFields;
		}

		protected virtual ISecurityPrincipal createPrinciple(IBizObj user)
        {
            ISecurityPrincipal security = 
				Application.currentApp.securityMgr.createPrincipal((string)user.get("userName"), user, null);
            Application.currentApp.securityMgr.currentPrincipal = security;
            foreach (IResourceSet rset in ((IDictionary)security.resourceSets).Values)
                if (!rset.isPopulated)
                    rset.populateResources();

            return security;
        }
    }

    /// <summary>
    /// Used as the return value and status for user login attempts from the loginAnonymousUser
    /// and loginUser bizrules.
    /// </summary>
 	public enum UserLoginResult  
	{
		ValidUserPassword,
		InvalidUserPassword,
		UserCompanyDisabled,
		UserAccountDisabled
	}
}
